﻿using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerUI;
using System;
using System.IO;
using System.Text;
using Lynn.Infastructure.Aop.Jwt;
using Lynn.Infastructure.Aop.Middleware;
using Lynn.Infastructure.Aop.Model;

namespace Lynn.Infastructure.Aop
{
    public static class AopServer
    {
        #region JWT
        /// <summary>
        /// 添加jwt
        /// </summary>
        /// <param name="services"></param>
        /// <param name="config"></param>
        /// <returns></returns>
        public static IServiceCollection AddJwt(this IServiceCollection services, Action<JwtOption> action)
        {
            var opt = new JwtOption();
            action.Invoke(opt);
            services.AddAuthentication((x)=>{
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(options =>
            {
                options.RequireHttpsMetadata = false;
                options.SaveToken = true;
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidIssuer = opt.Issuer,
                    ValidAudience = opt.Audience,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(opt.Key)),
                    ValidateIssuer = false,
                    ValidateAudience = false,
                    ValidateIssuerSigningKey = true
                };
                options.Events = new JwtBearerEvents {
                    //此处为权限验证失败后触发的事件
                    OnChallenge = context =>
                    {
                        throw new Error(ErrorType.尚未登录.ToString(), (int)ErrorType.尚未登录);
                    }
                };
            });
            services.AddSingleton(f =>
            {
                return new JwtBuilder(opt);
            });
            return services;
        }
        #endregion

        #region 结果封装中间件
        public static IApplicationBuilder UseResultBind(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<ResultMiddleware>();
        }
        #endregion

        #region API文档
        /// <summary>
        /// 添加文档 
        /// </summary>
        /// <param name="services"></param>
        /// <param name="info">问的那个描述信息</param>
        /// <param name="xmls">xml名称 需要放在根目录</param>
        /// <returns></returns>
        public static IServiceCollection AddApiDoc(this IServiceCollection services, OpenApiInfo info, params string[] xmls)
        {
            services.AddSwaggerGen(options =>
            {
                options.SwaggerDoc("api", info);
                //描述文件
                var path = AppDomain.CurrentDomain.BaseDirectory;
                foreach (var xmlpath in xmls)
                {
                    var xml = Path.Combine(path, xmlpath);
                    options.IncludeXmlComments(xml);
                }
            });
            return services;
        }
        /// <summary>
        /// 文档中间件 注意放置位置
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="des">描述信息</param>
        /// <param name="basePath">基地址</param>
        /// <returns></returns>
        public static IApplicationBuilder UseApiDoc(this IApplicationBuilder builder, string des = "接口文档",string basePath="")
        {
            builder.UseSwagger();
            builder.UseSwaggerUI(c =>
            {
                if (!string.IsNullOrWhiteSpace(basePath))
                {
                    basePath = "/" + basePath.TrimStart('/').TrimEnd('/');
                }
                c.SwaggerEndpoint($"{basePath}/swagger/api/swagger.json", des);
                c.DocExpansion(DocExpansion.None);
            });
            return builder;
        }
        #endregion
    }
}
